﻿using System;
using System.Collections.Generic;
#if DEBUG
using System.Diagnostics;
#endif // #if DEBUG
using System.Linq;
using System.Text;
using System.Data.Objects.DataClasses;

namespace FRL.DebtChased.Repository
{

	/// <summary>
	/// Extensions to the UserAction model
	/// </summary>
	public partial class UserAction
	{

		/////////////////////////////////////////////////////////////
		// Nested classes

		public class Delta
		{

			/////////////////////////////////////////////////////////
			// Attributes

			public EntityObject EntityObject { get; set; }

			public string Name { get; set; }

			public string Summary { get; set; }

			internal eActionType m_actionType = eActionType.NotSet;

			private string m_strTableName = null;
			private int m_iPrimaryKey = 0;

			/////////////////////////////////////////////////////////
			// Construction

			public Delta(EntityObject entityObject)
			{

				// Initialize member variables
				this.EntityObject = entityObject;
				this.m_iPrimaryKey = GetPrimaryKey();
				this.m_strTableName = GetTableName();

				// Compare entity states
				if (this.EntityObject.EntityState == System.Data.EntityState.Added)
					m_actionType = eActionType.Insert;
				else if (this.EntityObject.EntityState == System.Data.EntityState.Deleted)
					m_actionType = eActionType.Delete;
				else
					m_actionType = eActionType.Update;

			}

			/////////////////////////////////////////////////////////
			// Operations

			public int GetPrimaryKey()
			{

				// If primary key not known...
				if (m_iPrimaryKey == 0)
				{

					// Get entity key
					if (
						(this.EntityObject.EntityKey != null)
						&&
						(this.EntityObject.EntityKey.EntityKeyValues != null)
						&&
						(this.EntityObject.EntityKey.EntityKeyValues.Length > 0)
					)
						m_iPrimaryKey = (int)this.EntityObject.EntityKey.EntityKeyValues.ElementAt(0).Value;

				}

				// Return variable
				return m_iPrimaryKey;

			}

			public string GetTableName()
			{

				// If the table name is not known...
				if (m_strTableName == null)
				{

					// If entity is loaded...
					if (this.EntityObject.EntityKey != null)
					{

						// lookup name
						m_strTableName = string.Format("tb{0}", this.EntityObject.EntityKey.EntitySetName);

						// Get the table name
						if (m_strTableName == "tbAccountInvoiceStatus")
							m_strTableName = "tbAccountInvoiceStatus";
						else if (m_strTableName == "tbClientInstructionBatches")
							m_strTableName = "tbClientInstructionBatch";
						else if (m_strTableName == "tbCommBodies")
							m_strTableName = "tbCommBody";
						else if (m_strTableName.EndsWith("s"))
							m_strTableName = m_strTableName.Substring(0, m_strTableName.Length - 1);

						// Check table name
#if DEBUG
						Debug.Assert(
							(m_strTableName == "tbAgent")
							||
							(m_strTableName == "tbAgentContact")
							||
							(m_strTableName == "tbDocument")
							||
							(m_strTableName == "tbAgentBankAccount")
							||
							(m_strTableName == "tbAccountInvoiceStatus")
							||
							(m_strTableName == "tbClientWorkflowAssignment")
							||
							(m_strTableName == "tbClientCollectorAssignment")
							||
							(m_strTableName == "tbClientInstructionBatch")
							||
							(m_strTableName == "tbClientBankAccount")
							||
							(m_strTableName == "tbCommBody")
							||
							(m_strTableName == "tbAccountTradingStyle")
							||
							(m_strTableName == "tbSystemConfig")
							||
							(m_strTableName == "tbClientAlert")
							||
							(m_strTableName == "tbCommTemplate")
							||
							(m_strTableName == "tbWorkflow")
							||
							(m_strTableName == "tbAgent")
							||
							(m_strTableName == "tbClient")
							||
							(m_strTableName == "tbLetterType")
							||
							(m_strTableName == "tbUser")
							||
							(m_strTableName == "tbClientContact")
						);
#endif // #if DEBUG

					}

				}

				// Return variable
				return m_strTableName;

			}

		}

		public class Session : Delta
		{

			/////////////////////////////////////////////////////////////
			// Attributes

			private List<Delta> m_childDeltaList = new List<Delta>();

			private int m_iUserId = 0;

			/////////////////////////////////////////////////////////
			// Construction

			public Session( int iUserId, EntityObject entityObject, string strName )
				:base(entityObject)
			{

				// Initialize member variables
				base.Name = strName;
				this.m_iUserId = iUserId;

			}

			/////////////////////////////////////////////////////////////
			// Operations

			public bool HasChanges()
			{

				// Check primary delta
				if (this.EntityObject.EntityState != System.Data.EntityState.Unchanged)
					return true;

				// Check child deltas
				for( int i1=0; i1 < m_childDeltaList.Count; i1++ )
				{
					if(m_childDeltaList[i1].EntityObject.EntityState != System.Data.EntityState.Unchanged)
						return true;
				}

				// No changes
				return false;

			}

			public void SaveChanges( DebtChasedEntities ent )
			{

				// Declaration of local variables
				DateTime dtNow = DateTime.Now;

				try
				{

					// Add primary change
					UserAction primaryUserAction = UserAction.CreateUserAction(
						0,
						m_iUserId,
						base.GetPrimaryKey(),
						(int)base.m_actionType,
						dtNow,
						base.GetTableName()
					);
					primaryUserAction.RecordName = base.Name;
					primaryUserAction.ChangesSummary = base.Summary;
					ent.UserActions.AddObject(primaryUserAction);

					// Loop through the modifications
					foreach (var d in this.m_childDeltaList)
					{

						// If the child is modified...
						if (d.m_actionType != eActionType.NotSet)
						{

							// Add child delta record
							UserAction childUserAction = UserAction.CreateUserAction(
								0,
								m_iUserId,
								d.GetPrimaryKey(),
								(int)d.m_actionType,
								dtNow,
								d.GetTableName()
							);
							childUserAction.UserActionParent = primaryUserAction;
							childUserAction.RecordName = d.Name;
							childUserAction.ChangesSummary = d.Summary;
							ent.UserActions.AddObject(childUserAction);

						}

					}

					// Save changes
					ent.SaveChanges();

				}
				catch (Exception x)
				{

					// Save error, but don't show it
					ErrorProcessing.HandleException(x, "save user actions", m_iUserId);

				}

			}

			public Delta AddChildDelta( EntityObject entityObject, string strName, string strSummary=null )
			{
				
				// Declare a return variable
				Delta Ftmp = new Delta(entityObject)
				{
					Name = strName,
					Summary = strSummary
				};
				m_childDeltaList.Add(Ftmp);

				// Return variable
				return Ftmp;

			}

		}

		/////////////////////////////////////////////////////////////
		// Enumerations

		public enum eActionType
		{
			NotSet = 0,
			Insert = 1,
			Update = 2,
			Delete = 3,
		}

		/////////////////////////////////////////////////////////////
		// Attributes

		public eActionType ActionType
		{
			get { return (eActionType)this.fdAction; }
			set { this.fdAction = (int)value; }
		}

	}

}
